package com.biz.primus.ms.base.service;

import com.biz.primus.base.redis.CrudRedisDao;
import com.biz.primus.base.redis.bean.BaseRedisObject;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * 数据同步接口,要求所有需要保存到redis的实体的service实现此接口,以便于将mysql中的数据同步到redis中
 *
 * @author yanweijin
 * @usage 见{@link com.bozhi.search.user.UserServiceHelper}中对该方法的实现方式
 * @reviewer
 * @since 2016年8月16日
 */
public interface DataSyncService {

    /**
     * 将mysql数据同步到redis,请自行分页
     *
     * @author yanweijin
     * @date 2016年8月16日
     */
    @Transactional(noRollbackFor = Throwable.class, propagation = Propagation.REQUIRES_NEW)
    void syncMysql2Redis();

    /**
     * 数据同步助手,传入PO,RO对应的repository,以及将po转换为ro的function,即可同步数据
     *
     * @author yanweijin
     * @usage
     * @reviewer
     * @since 2016年8月16日
     */
    class DataSyncHelper {
        /**
         * 便捷同步方式
         *
         * @param repo     PO的repository
         * @param redisDao RO的redisDao
         * @param func     将PO转换为RO的function
         * @author yanweijin
         * @date 2016年8月16日
         */
        public static <PO, RO extends BaseRedisObject<? extends Number>> void syncData(
                JpaRepository<PO, ? extends Number> repo,
                CrudRedisDao<RO, ? extends Number> redisDao,
                final Function<PO, RO> func
        ) {
            /*
			 * [0] Thread.getStackTrace
			 * [1] DataSyncHelper.syncData
			 * [2] syncMysql2Redis(及实现类)
			 */
            final StackTraceElement signature = Thread.currentThread().getStackTrace()[2];
            Page<PO> page = null;
            for (Pageable pageable = new PageRequest(0, 1000);
                 (page = repo.findAll(pageable)).hasContent();
                 pageable = pageable.next()
                    ) {
                List<PO> content = page.getContent();
                List<RO> roList = Lists.transform(content, input -> {
                    try {
                        return func.apply(input);
                    } catch (Exception e) {
                        e.printStackTrace();
                        return null;
                    }
                });
                for (RO ro : roList) {
                    redisDao.save(ro);
                }
//				redisDao.save(roList);
            }
        }
    }
}
